home *** CD-ROM | disk | FTP | other *** search
- /*
- * Name: MUS File Player
- * Version: 1.50
- * Author: Vladimir Arnost (QA-Software)
- * Last revision: Oct-30-1994
- * Compiler: Borland C++ 3.1
- *
- */
-
- /*
- * Revision History:
- *
- * Aug-8-1994 V1.00 V.Arnost
- * Written from scratch
- * Aug-9-1994 V1.10 V.Arnost
- * Some minor changes to improve sound quality. Tried to add
- * stereo sound capabilities, but failed to -- my SB Pro refuses
- * to switch to stereo mode.
- * Aug-13-1994 V1.20 V.Arnost
- * Stereo sound fixed. Now works also with Sound Blaster Pro II
- * (chip OPL3 -- gives 18 "stereo" (ahem) channels).
- * Changed code to handle properly notes without volume.
- * (Uses previous volume on given channel.)
- * Added cyclic channel usage to avoid annoying clicking noise.
- * Aug-17-1994 V1.30 V.Arnost
- * Completely rewritten time synchronization. Now the player runs
- * on IRQ 8 (RTC Clock - 1024 Hz).
- * Aug-28-1994 V1.40 V.Arnost
- * Added Adlib and SB Pro II detection.
- * Fixed bug that caused high part of 32-bit registers (EAX,EBX...)
- * to be corrupted.
- * Oct-30-1994 V1.50 V.Arnost
- * Tidied up the source code
- * Added C key - invoke COMMAND.COM
- * Added RTC timer interrupt flag check (0000:04A0)
- * Added BLASTER environment variable parsing
- * FIRST PUBLIC RELEASE
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include <string.h>
- #include <mem.h>
- #include <bios.h>
- #include <dos.h>
- #include <conio.h>
- #include "adlib.h"
-
- #define VERSION "1.50"
- #define COPYRIGHT "MUS File Player Version "VERSION" (c) 1994 QA-Software"
-
- /* Global type declarations */
-
- #ifdef __386__
- typedef unsigned long DWORD;
- #else
- typedef unsigned char BYTE;
- typedef unsigned int WORD;
- typedef unsigned long DWORD;
- #endif
-
- #if __BORLANDC__ >= 0x300 // BC 3.1: in you want to compile in 386 mode,
- #define FASTCALL _fastcall // undef this #define
- #else
- #define FASTCALL
- #endif
-
- //#define DEBUG // turn on debugging messages
- //#define NOIRQ // turn on non-interrupt-driven player
-
- #define CHANNELS 16 // total channels 0..CHANNELS-1
- #define PERCUSSION 15 // percussion channel
-
- #define INSTRSIZE 36 // instrument size (in bytes)
-
- struct MUSheader {
- char ID[4]; // identifier "MUS" 0x1A
- WORD scoreLen;
- WORD scoreStart;
- WORD channels;
- WORD dummy1;
- WORD instrCnt;
- WORD dummy2;
- // WORD instruments[];
- } header;
-
- #ifdef DEBUG
- #include "musinstr.c" // instrument names (for debugging)
- #endif
-
-
- WORD SBProPort = SBPROPORT;
- WORD channelInstr[CHANNELS]; // instrument #
- BYTE channelVolume[CHANNELS]; // volume
- BYTE channelLastVolume[CHANNELS]; // last volume
- signed char channelPan[CHANNELS]; // pan, 0=normal
- signed char channelPitch[CHANNELS]; // pitch wheel, 0=normal
- DWORD Adlibtime[OUTPUTCHANNELS]; // Adlib channel start time
- WORD Adlibchannel[OUTPUTCHANNELS]; // Adlib channel & note #
- BYTE Adlibnote[OUTPUTCHANNELS]; // Adlib channel note
- BYTE *Adlibinstr[OUTPUTCHANNELS]; // Adlib channel instrument address
- BYTE Adlibvolume[OUTPUTCHANNELS]; // Adlib channel volume
- signed char Adlibfinetune[OUTPUTCHANNELS];// Adlib 2nd channel pitch difference
- #ifdef NOIRQ
- DWORD speed = 6832;
- #endif
-
- void interrupt (*oldint70h)(void);
- WORD far *timerstack = NULL;
- WORD far *timerstackend = NULL;
- volatile WORD far *timersavestack = NULL;
- volatile DWORD MUStime;
- volatile BYTE *MUSdata;
- volatile DWORD MUSticks;
- volatile WORD playingAtOnce = 0;
- volatile WORD playingPeak = 0;
- volatile WORD playingChannels = 0;
-
- BYTE *score;
- BYTE *instruments;
-
- /* Command-line parameters */
- char *musname = NULL;
- char *instrname = "GENMIDI.OP2";
- int help = 0;
- int singlevoice = 0;
- int stereo = 1;
- char *execCmd = NULL;
- int loopForever = 0;
-
- int readMUS(FILE *f)
- {
- if (fread(&header, sizeof(BYTE), sizeof header, f) != sizeof header)
- {
- puts("Unexpected end of file.");
- return -1;
- }
-
- if (header.ID[0] != 'M' ||
- header.ID[1] != 'U' ||
- header.ID[2] != 'S' ||
- header.ID[3] != 0x1A)
- {
- puts("Bad file.");
- return -1;
- }
-
- fseek(f, header.scoreStart, SEEK_SET);
-
- if ( (score = malloc(header.scoreLen)) == NULL)
- {
- puts("Not enough memory.");
- return -1;
- }
-
- if (fread(score, sizeof(BYTE), header.scoreLen, f) != header.scoreLen)
- {
- puts("Unexpected end of file.");
- return -1;
- }
-
- return 0;
- }
-
- int readINS(FILE *f)
- {
- char hdr[8];
- static char masterhdr[8] = {'#','O','P','L','_','I','I','#'};
-
- if (fread(&hdr, sizeof(BYTE), sizeof hdr, f) != sizeof hdr)
- {
- puts("Unexpected end of instrument file.");
- return -1;
- }
- if (memcmp(hdr, masterhdr, sizeof hdr))
- {
- puts("Bad instrument file.");
- return -1;
- }
- if ( (instruments = calloc(175, INSTRSIZE)) == NULL)
- {
- puts("Not enough memory.");
- return -1;
- }
- if (fread(instruments, INSTRSIZE, 175, f) != 175)
- {
- puts("Unexpected end of instrument file.");
- return -1;
- }
- return 0;
- }
-
- static WORD freqtable[] = {
- 172, 183, 194, 205, 217, 230, 244, 258, 274, 290, 307, 326,
- 345, 365, 387, 410, 435, 460, 488, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 517, 547, 580, 615, 651,
- 690, 731, 774, 820, 869, 921, 975, 1023, 1023, 1023, 1023, 1023,
- 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1023};
- static char octavetable[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1};
-
- void WriteFrequency(BYTE Adlibchannel, WORD note, int pitch, BYTE keyOn)
- {
- WORD freq = freqtable[note];
- WORD octave = octavetable[note];
-
- if (pitch > 0)
- {
- int freq2;
- int octave2 = octavetable[note+1] - octave;
-
- #ifdef DEBUG
- printf("DEBUG: pitch: N: %d P: %d\n", note, pitch);
- #endif
-
- if (octave2)
- {
- octave++;
- freq >>= 1;
- }
- freq2 = freqtable[note+1] - freq;
- freq += (freq2 * pitch) / 64;
- } else
- if (pitch < 0)
- {
- int freq2;
- int octave2 = octave - octavetable[note-1];
-
- #ifdef DEBUG
- printf("DEBUG: pitch: N: %d P: %d\n", note, pitch);
- #endif
-
- if (octave2)
- {
- octave--;
- freq <<= 1;
- }
- freq2 = freq - freqtable[note-1];
- freq -= (freq2 * -pitch) / 64;
- }
- WriteFreq(Adlibchannel, freq, octave, keyOn);
- }
-
- int OccupyChannel(WORD i, WORD channel, BYTE note, int volume, BYTE *instr,
- WORD flag)
- {
- playingChannels++;
- Adlibchannel[i] = (channel << 8) | note | (flag << 15);
- Adlibtime[i] = MUStime;
- if (volume == -1)
- volume = channelLastVolume[channel];
- else
- channelLastVolume[channel] = volume;
- volume = channelVolume[channel] * (Adlibvolume[i] = volume) / 127;
- if (instr[0] & 1)
- note = instr[3];
- else if (channel == PERCUSSION)
- note = 60; // C-5
- if (flag && (instr[0] & 4))
- Adlibfinetune[i] = instr[2] - 0x80;
- else
- Adlibfinetune[i] = 0;
- if (flag)
- instr += 16+4;
- else
- instr += 4;
- WriteInstrument(i, Adlibinstr[i] = instr);
- WritePan(i, instr, channelPan[channel]);
- WriteVolume(i, instr, volume);
- Adlibnote[i] = note += instr[14] + 12;
- WriteFrequency(i, note, Adlibfinetune[i]+channelPitch[channel], 1);
- return i;
- }
-
- int ReleaseChannel(WORD i, WORD killed)
- {
- WORD channel = (Adlibchannel[i] >> 8) & 0x7F;
- #ifdef DEBUG
- printf("\nDEBUG: Release Ch: %d Adl: %d %04X\n", channel, i, Adlibchannel[i]);
- #endif
- playingChannels--;
- WriteFrequency(i, Adlibnote[i], Adlibfinetune[i]+channelPitch[channel], 0);
- Adlibchannel[i] = 0xFFFF;
- if (killed)
- {
- WriteChannel(0x80, i, 0x0F, 0x0F); // release rate - fastest
- WriteChannel(0x40, i, 0x3F, 0x3F); // no volume
- }
- return i;
- }
-
- int FindFreeChannel(WORD flag)
- {
- static WORD last = 0xFFFF;
- WORD i;
- WORD latest = 0xFFFF;
- DWORD latesttime = MUStime;
-
- for(i = 0; i < AdlibChannels; i++)
- {
- if (++last == AdlibChannels)
- last = 0;
- if (Adlibchannel[last] == 0xFFFF)
- return last;
- }
-
- if (flag & 1)
- return -1;
-
- for(i = 0; i < AdlibChannels; i++)
- {
- if ((Adlibchannel[i] & 0x8000))
- {
- #ifdef DEBUG
- printf("\nDEBUG: Kill 2nd %04X\n", Adlibchannel[i]);
- #endif
- ReleaseChannel(i, -1);
- return i;
- } else
- if (Adlibtime[i] < latesttime)
- {
- latesttime = Adlibtime[i];
- latest = i;
- }
- }
-
- if ( !(flag & 2) && latest != 0xFFFF)
- {
- #ifdef DEBUG
- printf("DEBUG: Kill %04X !!!\n", Adlibchannel[latest]);
- #endif
- ReleaseChannel(latest, -1);
- return latest;
- }
-
- #ifdef DEBUG
- printf("DEBUG: Full!!!\n");
- #endif
- return -1;
- }
-
- // code 1: play note
- void playNote(WORD channel, BYTE note, int volume)
- {
- int i; // orignote = note;
- BYTE *instr, instrnumber;
-
- if (channel == PERCUSSION)
- {
- if (note < 35 || note > 81)
- return; // wrong percussion number
- instrnumber = (128-35) + note;
- } else
- instrnumber = channelInstr[channel];
- instr = &instruments[instrnumber*INSTRSIZE];
- #ifdef DEBUG
- cprintf("\rDEBUG: play: Ch: %d N: %d V: %d (%d) I: %d (%s) Fi: %d\r\n",
- channel, note, volume, channelVolume[channel], instrnumber, instrumentName[instrnumber],
- (instr[0] & 4) ? (instr[2] - 0x80) : 0);
- #endif
-
- if ( (i = FindFreeChannel((channel == PERCUSSION) ? 2 : 0)) != -1)
- {
- OccupyChannel(i, channel, note, volume, instr, 0);
- if (!singlevoice && instr[0] == 4)
- {
- if ( (i = FindFreeChannel((channel == PERCUSSION) ? 3 : 1)) != -1)
- OccupyChannel(i, channel, note, volume, instr, 1);
- }
- }
- }
-
- // code 0: release note
- void releaseNote(WORD channel, BYTE note)
- {
- WORD i;
-
- #ifdef DEBUG
- printf("DEBUG: release: Ch: %d N: %d\n", channel, note);
- #endif
- channel = (channel << 8) | note;
- for(i = 0; i < AdlibChannels; i++)
- if ((Adlibchannel[i] & 0x7FFF) == channel)
- {
- ReleaseChannel(i, 0);
- // return;
- }
- }
-
- // code 2: change pitch wheel (bender)
- void pitchWheel(WORD channel, int pitch)
- {
- WORD i;
-
- #ifdef DEBUG
- printf("DEBUG: pitch: Ch: %d P: %d\n", channel, pitch);
- #endif
- channelPitch[channel] = pitch;
- for(i = 0; i < AdlibChannels; i++)
- if (((Adlibchannel[i] >> 8) & 0x7F) == channel)
- {
- Adlibtime[i] = MUStime;
- WriteFrequency(i, Adlibnote[i], Adlibfinetune[i]+pitch, 1);
- }
- }
-
- // code 4: change control
- void changeControl(WORD channel, BYTE controller, int value)
- {
- WORD i;
- #ifdef DEBUG
- printf("DEBUG: ctrl: Ch: %d C: %d V: %d\n", channel, controller, value);
- #endif
-
- switch (controller) {
- case 0: // change instrument
- channelInstr[channel] = value;
- break;
- case 3: // change volume
- channelVolume[channel] = value;
- for(i = 0; i < AdlibChannels; i++)
- if (((Adlibchannel[i] >> 8) & 0x7F) == channel)
- {
- Adlibtime[i] = MUStime;
- WriteVolume(i, Adlibinstr[i], value * Adlibvolume[i] / 127);
- }
- break;
- case 4: // change pan (balance)
- channelPan[channel] = value -= 64;
- for(i = 0; i < AdlibChannels; i++)
- if (((Adlibchannel[i] >> 8) & 0x7F) == channel)
- {
- Adlibtime[i] = MUStime;
- WritePan(i, Adlibinstr[i], value);
- }
- break;
- }
- }
-
- BYTE *playTick(BYTE *data)
- {
- for(;;) {
- BYTE command = (*data >> 4) & 7;
- BYTE channel = *data & 0x0F;
- BYTE last = *data & 0x80;
- data++;
-
- switch (command) {
- case 0: // release note
- playingAtOnce--;
- releaseNote(channel, *data++);
- break;
- case 1: { // play note
- BYTE note = *data++;
- playingAtOnce++;
- if (playingAtOnce > playingPeak)
- playingPeak = playingAtOnce;
- if (note & 0x80) // note with volume
- playNote(channel, note & 0x7F, *data++);
- else
- playNote(channel, note, -1);
- } break;
- case 2: // pitch wheel
- pitchWheel(channel, *data++ - 0x80);
- break;
- case 4: // change control
- changeControl(channel, data[0], data[1]);
- data += 2;
- break;
- case 6: // end
- return NULL;
- case 5: // ???
- case 7: // ???
- break;
- case 3: // set tempo ??? -- ignore it
- data++;
- break;
- }
- if (last)
- break;
- }
- return data;
- }
-
- BYTE *delayTicks(BYTE *data, DWORD *delaytime)
- {
- DWORD time = 0;
-
- do {
- time <<= 7;
- time += *data & 0x7F;
- } while (*data++ & 0x80);
-
- *delaytime = time;
- return data;
- }
-
- #ifdef NOIRQ
- void playMUS(void)
- {
- BYTE *data = score;
- DWORD ticks = 0, playtime = 0;
- WORD i;
- volatile BYTE flag = 0;
-
- if (stereo)
- InitAdlib(SBProPort, 1);
- else
- InitAdlib(ADLIBPORT, 0);
-
- setmem(Adlibchannel, sizeof Adlibchannel, 0xFF);
- for (i = 0; i < CHANNELS; i++)
- {
- channelVolume[i] = 127; // default volume 127 (full volume)
- channelLastVolume[i] = 100;
- }
- MUStime = 0;
-
- for(;;) {
- DWORD temp;
- /* Bios INT 15h, Fn 8300h -- Start timer */
- flag = 0; // byte to be set when the interval elapses
- asm {
- push ds
- push bp
- mov dx,WORD PTR speed[0] // CX:DX - interval (in microseconds)
- mov cx,WORD PTR speed[2]
- push ss
- pop es
- lea bx,flag // ES:BX - flag address
- mov ax,8300h // start timer
- int 15h
- pop bp
- pop ds
- }
- playingPeak = playingAtOnce;
- if (!ticks)
- {
- #ifdef DEBUG
- // printf("DEBUG: data = %p\n", data);
- #endif
- data = playTick(data);
- if (data == NULL)
- break;
- data = delayTicks(data, &ticks);
- #ifdef DEBUG
- puts("------------------------------");
- #endif
- }
- ticks--;
- MUStime++;
- // show playing time (not too accurate, though)
- playtime += speed;
- // temp = playtime / 1000;
- temp = (MUStime*1000)/128;
- cprintf("\rPlaying ... %2ld:%02ld:%03ld %2d (%2d)", temp / 60000,
- (temp / 1000) % 60, temp % 1000, playingAtOnce, playingChannels);
- if (bioskey(1) == 0x011B) // Esc - exit to DOS
- break;
- if ( !(bioskey(2) & 3) ) // Shift Key - full speed ahead!
- while (!flag); // synchronization
- }
- asm {
- mov ax,8301h // cancel timer
- int 15h
- }
- printf("\n");
-
- DeinitAdlib();
- }
-
- #else // NOIRQ
-
- void playMusic(void)
- {
- BYTE keyflags = *(BYTE far *)MK_FP(0x0040, 0x0018);
-
- playingPeak = playingAtOnce;
- if (!MUSdata) return;
- if (!MUSticks || keyflags & 4)
- {
- MUSdata = playTick((BYTE *)MUSdata);
- if (MUSdata == NULL)
- {
- if (loopForever)
- MUSdata = score;
- return;
- }
- MUSdata = delayTicks((BYTE *)MUSdata, &(DWORD)MUSticks);
- MUSticks = (MUSticks * 75) / 10;
- // MUSticks *= 8;
- MUStime += MUSticks;
- }
- MUSticks--;
- // MUStime++;
- }
-
- void FASTCALL CMOSwrite(BYTE reg, BYTE value)
- {
- asm {
- mov al,reg
- out 70h,al
- jmp delay1
- }
- delay1: asm jmp delay2
- delay2: asm {
- mov al,value
- out 71h,al
- }
- }
-
- int FASTCALL CMOSread(BYTE reg)
- {
- asm {
- mov al,reg
- out 70h,al
- jmp delay1
- }
- delay1: asm jmp delay2
- delay2: asm {
- in al,71h
- xor ah,ah
- }
- return _AX;
- }
-
- void interrupt newint70h_handler(void)
- {
- static WORD count = 0;
-
- if ( ! (CMOSread(0x0C) & 0x40) )
- {
- (*oldint70h)();
- return;
- }
-
- if (!count)
- {
- count++;
- asm {
- mov WORD PTR timersavestack[2],ss
- mov WORD PTR timersavestack[0],sp
- mov ss,WORD PTR timerstackend[2]
- mov sp,WORD PTR timerstackend[0]
- db 66h; pusha // *386* pushad
- }
- playMusic();
- asm {
- db 66h; popa // *386* popad
- nop // workaround against 386 POPAD bug
- mov ss,WORD PTR timersavestack[2]
- mov sp,WORD PTR timersavestack[0]
- }
- count--;
- }
-
- asm {
- mov al,20h // end-of-interrupt
- out 0A0h,al
- jmp delay1
- }
- delay1: asm out 20h,al
- }
-
- int SetupTimer(void)
- {
- if ( *(BYTE far *)MK_FP(0x0000, 0x04A0) ) // is the timer busy?
- return -1;
- if ( (timerstack = calloc(0x100, sizeof(WORD))) == NULL)
- return -1;
- *(BYTE far *)MK_FP(0x0000, 0x04A0) = 1; // mark the timer as busy
- timerstackend = &timerstack[0x100];
- oldint70h = getvect(0x70);
- setvect(0x70, newint70h_handler);
- CMOSwrite(0x0B, CMOSread(0x0B) | 0x40); // enable periodic interrupt
- asm {
- in al,0A1h // enable IRQ 8
- and al,0FEh
- out 0A1h,al
- }
- return 0;
- }
-
- int ShutdownTimer(void)
- {
- CMOSwrite(0x0B, CMOSread(0x0B) & ~0x40); // disable periodic interrupt
- asm {
- in al,0A1h // disable IRQ 8
- or al,1
- out 0A1h,al
- }
- setvect(0x70, oldint70h);
- free(timerstack);
- *(BYTE far *)MK_FP(0x0000, 0x04A0) = 0; // mark the timer as unused
- return 0;
- }
-
- void playMUS(void)
- {
- DWORD lasttime;
- WORD i;
-
- if (stereo)
- InitAdlib(SBProPort, 1);
- else
- InitAdlib(ADLIBPORT, 0);
-
- setmem(Adlibchannel, sizeof Adlibchannel, 0xFF);
- for (i = 0; i < CHANNELS; i++)
- {
- channelVolume[i] = 127; // default volume 127 (full volume)
- channelLastVolume[i] = 100;
- }
-
- MUSdata = score;
- MUSticks = 0;
- MUStime = 0;
- lasttime = 0xFFFFFFFF;
-
- if (SetupTimer())
- {
- printf("FATAL ERROR: Cannot initialize 1024 Hz timer. Aborting.\n");
- return;
- }
-
- if (execCmd)
- system(execCmd);
-
- for(;;) {
- if (!MUSdata) // no more music
- break;
- if (bioskey(1))
- {
- WORD key = bioskey(0);
- if (key == 0x011B) // Esc - exit to DOS
- break;
- else if ((BYTE)key == 'c' || (BYTE)key == 'C')
- system(""); // C - run COMMAND.COM
- }
- if (lasttime != MUStime)
- {
- DWORD playtime = ((lasttime = MUStime)*1000)/1024;
- cprintf("\rPlaying ... %2ld:%02ld:%03ld %2d (%2d)", playtime / 60000,
- (playtime / 1000) % 60, playtime % 1000, playingAtOnce, playingChannels);
- }
- }
- ShutdownTimer();
- cprintf("\r\n");
-
- DeinitAdlib();
- }
- #endif // NOIRQ
-
- int detectHardware(void)
- {
- DetectBlaster(&SBProPort, NULL, NULL, NULL);
- if (!DetectAdlib(ADLIBPORT))
- return -1;
- return DetectSBProII(SBProPort);
- }
-
- int dispatchOption(char *option)
- {
- switch (*option) {
- case '?':
- case 'H': // help
- help = 1;
- break;
- case 'B': // instrument bank
- instrname = option+1;
- break;
- #ifdef NOIRQ
- case 'S': // speed
- speed = strtoul(option+1, NULL, 0);
- break;
- #endif
- case '1': // single voice
- singlevoice = 1;
- break;
- case 'M': // mono mode
- stereo = 0;
- break;
- case 'C': // command
- execCmd = option+1;
- break;
- case 'L': // loop
- loopForever = 1;
- break;
- default:
- return -1;
- }
- return 0;
- }
-
- main(int argc, char *argv[])
- {
- FILE *f;
-
- puts(COPYRIGHT);
- while (argv++, --argc)
- {
- strupr(*argv);
- if (**argv == '/' || **argv == '-')
- {
- if (dispatchOption(*argv+1))
- {
- printf("Invalid option %s\n", *argv);
- return 2;
- }
- } else {
- if (!musname)
- musname = *argv;
- else {
- printf("Too many filenames.\n");
- return 3;
- }
- }
- }
-
- if (!musname || help)
- {
- puts("Syntax:\n"
- " MUSPLAY filename.MUS [/B[path\]GENMIDI.OP2] [/1] [/M] [/Ccmd] [/L]\n"
- "Options:\n"
- " /Bbank set different instrument bank\n"
- #ifdef NOIRQ
- " /Sspeed change duration of one time-tick (default 6832 microseconds)\n"
- #endif
- " /1 don't use double-voice instruments\n"
- " /M play in mono -- thru Adlib instead of SoundBlaster Pro II\n"
- " /Ccmd exec DOS command cmd during replay\n"
- " /L play continuously (loop forever)\n");
- return 1;
- }
-
- switch (detectHardware()) {
- case -1:
- puts("Adlib not detected. Exiting.");
- return 4;
- case 0:
- stereo = 0;
- puts("Adlib detected (9 channels mono)");
- break;
- case 1:
- puts("Sound Blaster Pro II detected (18 channels stereo)");
- break;
- }
-
- if ( (f = fopen(musname, "rb")) == NULL)
- {
- printf("Can't open file %s\n", musname);
- return 5;
- } else
- printf("Reading file %s ...\n", musname);
-
- if (readMUS(f))
- {
- fclose(f);
- return 6;
- }
- fclose(f);
-
- #ifdef DEBUG
- printf("DEBUG: coreleft = %lu\n", (long)coreleft());
- #endif
-
- if ( (f = fopen(instrname, "rb")) == NULL)
- {
- printf("Can't open file %s\n", instrname);
- return 7;
- } else
- printf("Reading file %s ...\n", instrname);
-
- if (readINS(f))
- {
- fclose(f);
- return 8;
- }
- fclose(f);
-
- #ifdef DEBUG
- printf("DEBUG: coreleft = %lu\n", (long)coreleft());
- #endif
-
- playMUS();
-
- free(score);
- free(instruments);
-
- return 0;
- }
-